import axios from 'axios'
import { ContentTypeEnum, successCode, checkStatus } from './config.js'
import { getStorage } from '@/utils/storage.js'
import { openMessage } from '@/utils/index.js'

export default class VAxios {
  constructor(options) {
    this.options = options
    console.log(this.#initialization(this.options))
    this.axiosInstance = axios.create(this.#initialization(this.options))
    const CancelToken = axios.CancelToken
    this.source = CancelToken.source()

    this.#setupInterceptors()

    this.stack = []
  }

  #initialization(params) {
    const options = {
      // `url` 是用于请求的服务器 URL
      url: params.apiUrl,
      // `method` 是创建请求时使用的方法
      method: params.method, // default
      baseURL: params.baseURL,
      // `headers` 是即将被发送的自定义请求头
      headers: { 'Content-Type': ContentTypeEnum[params.contentType] },
      timeout: params.timeout,
      // `responseType` 表示服务器响应的数据类型，可以是 'arraybuffer', 'blob', 'document', 'json', 'text', 'stream'
      responseType: params.responseType // default
    }
    if (params.otherHeader) {
      options.headers = {
        ...options.headers,
        ...params.otherHeader
      }
    }
    if (params.withToken) {
      const token = getStorage('TOKEN')
      if (token) {
        options.headers[ConfigEnum['TOKEN']] = `Bearer ${token}`
      }
    }
    return options
  }

  send(data) {
    return this.axiosInstance({
      [this.options.method == 'GET' ? 'params' : 'data']: data,
      method: this.options.method,
      url: this.options.apiUrl,
      cancelToken: this.source.token
    })
  }

  cancel(message) {
    this.source.cancel(message)
  }

  #setupInterceptors() {
    this.axiosInstance.interceptors.request.use(
      (config) => {
        if (this.#isExist(config.url)) return null
        if (this.options.ignoreCancelToken) {
          this.stack.push(config.url)
        }

        if (config.method == 'post' && this.options.joinParamsToUrl) {
          let params = config.data
          if (params && JSON.stringify(params) !== '{}') {
            let paramsList = []
            for (let key in params) {
              paramsList.push(`${key}=${params[key]}`)
            }
            config.url += `?${paramsList.join('&')}`
          }
        }
        if (this.options.joinTime) {
          const time = new Date().valueOf()
          config.headers['time-stamp'] = time
          if (config.params) {
            config.params.timeStamp = time
          } else {
            config.url += `${this.options.joinParamsToUrl ? '&' : '?'}timestamp=${time}`
          }
        }
        return config
      },
      (error) => {
        Promise.reject(error)
      }
    )

    this.axiosInstance.interceptors.response.use(
      (config) => {
        this.#removeShed(config.url)
        if (!successCode.includes(config.data.code)) {
          const message = checkStatus(config.data.code, config.data.message || config.data.msg)
          if (this.options.errorMessageMode === 'message') {
            openMessage(message, 'error')
          }
          return config.data
        } else {
          if (this.options.responseType != 'JSON' || this.options.isReturnNativeResponse) {
            return config
          } else {
            return config.data
          }
        }
      },
      (error) => {
        return {}
      }
    )
  }

  #isExist(url) {
    return this.stack.find((ele) => ele == url)
  }

  #removeShed(url) {
    const index = this.stack.findIndex((ele) => ele == url)
    this.stack.splice(index, 1)
  }
}
